﻿
#if BLAZE_TEXT_ENCODING

using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Text;

namespace Blaze.Text
{
    [Serializable]
    public class ReferenceSourceDefaultEncoder : Encoder, IObjectReference
    {
        private Encoding m_encoding;
        [NonSerialized]
        private bool m_hasInitializedEncoding;

        [NonSerialized]
        internal char charLeftOver;

        public ReferenceSourceDefaultEncoder(Encoding encoding)
        {
            m_encoding = encoding;
            m_hasInitializedEncoding = true;
        }

        // Constructor called by serialization, have to handle deserializing from Everett
        internal ReferenceSourceDefaultEncoder(SerializationInfo info, StreamingContext context)
        {
            if (info == null) throw new ArgumentNullException("info");

            // All we have is our encoding
            this.m_encoding = (Encoding)info.GetValue("encoding", typeof(Encoding));

            try
            {
                //this.m_fallback     = (EncoderFallback) info.GetValue("m_fallback",   typeof(EncoderFallback));
                this.charLeftOver = (Char)info.GetValue("charLeftOver", typeof(Char));
            }
            catch (SerializationException)
            {
            }
        }

        // Just get it from GetEncoding
        [System.Security.SecurityCritical]  // auto-generated
        public Object GetRealObject(StreamingContext context)
        {
            // upon deserialization since the DefaultEncoder implement IObjectReference the 
            // serialization code tries to do the fixup. The fixup returns another 
            // IObjectReference (the DefaultEncoder) class and hence so on and on. 
            // Finally the deserialization logics fails after following maximum references
            // unless we short circuit with the following
            if (m_hasInitializedEncoding)
            {
                return this;
            }

            Encoder encoder = m_encoding.GetEncoder();
            /*
            if (m_fallback != null)
                encoder.m_fallback = m_fallback;
            if (charLeftOver != (char) 0)
            {
                EncoderNLS encoderNls = encoder as EncoderNLS;
                if (encoderNls != null)
                    encoderNls.charLeftOver = charLeftOver;
            }
            */
            return encoder;
        }

#if FEATURE_SERIALIZATION
            // ISerializable implementation, get data for this object
            [System.Security.SecurityCritical]  // auto-generated_required
            void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
            {
                // Any info?
                if (info==null) throw new ArgumentNullException("info");
                Contract.EndContractBlock();

                // All we have is our encoding
                info.AddValue("encoding", this.m_encoding);
            }
#endif

        // Returns the number of bytes the next call to GetBytes will
        // produce if presented with the given range of characters and the given
        // value of the flush parameter. The returned value takes into
        // account the state in which the encoder was left following the last call
        // to GetBytes. The state of the encoder is not affected by a call
        // to this method.
        //

        public override int GetByteCount(char[] chars, int index, int count, bool flush)
        {
            return m_encoding.GetByteCount(chars, index, count);
        }

        [System.Security.SecurityCritical]  // auto-generated
        [SuppressMessage("Microsoft.Contracts", "CC1055")]  // Skip extra error checking to avoid *potential* AppCompat problems.
        public unsafe override int GetByteCount(char* chars, int count, bool flush)
        {
            return m_encoding.GetByteCount(chars, count);
        }

        // Encodes a range of characters in a character array into a range of bytes
        // in a byte array. The method encodes charCount characters from
        // chars starting at index charIndex, storing the resulting
        // bytes in bytes starting at index byteIndex. The encoding
        // takes into account the state in which the encoder was left following the
        // last call to this method. The flush parameter indicates whether
        // the encoder should flush any shift-states and partial characters at the
        // end of the conversion. To ensure correct termination of a sequence of
        // blocks of encoded bytes, the last call to GetBytes should specify
        // a value of true for the flush parameter.
        //
        // An exception occurs if the byte array is not large enough to hold the
        // complete encoding of the characters. The GetByteCount method can
        // be used to determine the exact number of bytes that will be produced for
        // a given range of characters. Alternatively, the GetMaxByteCount
        // method of the Encoding that produced this encoder can be used to
        // determine the maximum number of bytes that will be produced for a given
        // number of characters, regardless of the actual character values.
        //

        public override int GetBytes(char[] chars, int charIndex, int charCount,
                                      byte[] bytes, int byteIndex, bool flush)
        {
            return m_encoding.GetBytes(chars, charIndex, charCount, bytes, byteIndex);
        }

        [System.Security.SecurityCritical]  // auto-generated
        [SuppressMessage("Microsoft.Contracts", "CC1055")]  // Skip extra error checking to avoid *potential* AppCompat problems.
        public unsafe override int GetBytes(char* chars, int charCount,
                                             byte* bytes, int byteCount, bool flush)
        {
            return m_encoding.GetBytes(chars, charCount, bytes, byteCount);
        }
    }
}

#endif